package com.binguo.wxapi.service;

import com.binguo.common.exception.ServiceException;
import com.binguo.helper.WxAppHelper;
import com.binguo.model.model.Customer;
import com.binguo.model.model.WxOrderingUser;
import com.binguo.model.model.WxTempUser;
import com.binguo.model.repository.CustomerRepository;
import com.binguo.model.repository.WxOrderingUserRepository;
import com.binguo.model.repository.WxTempUserRepository;
import com.binguo.model.wxapi.dto.SessionDTO;
import com.binguo.model.wxapi.dto.UserInfoDTO;
import com.binguo.model.wxapi.vo.CustomerVO;
import com.binguo.service.CustomerService;
import com.binguo.wxapi.form.UserInfoDetailForm;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Condition;

import java.util.Optional;

import static com.binguo.common.exception.ErrorCode.WX_CREATE_CUSTOMER;
import static com.binguo.common.exception.ErrorCode.WX_CUSTOMER_NOT_EXIST;

/**
 * Created by haibang on 18/5/20.
 */
@Service
public class WXLoginService {

    @Autowired
    WxAppHelper wxAppHelper;

    @Autowired
    CustomerService customerService;

    @Autowired
    CustomerRepository customerRepository;

    @Autowired
    WxTempUserRepository wxTempUserRepository;

    @Autowired
    WxOrderingUserRepository wxOrderingUserRepository;

    @Autowired
    WXTokenService WXTokenService;

    public Optional<WxTempUser> getWxTempUserByOpenId(String openId) {
        Condition condition = new Condition(WxTempUser.class);
        condition.or().andEqualTo("openid", openId);
        Optional<WxTempUser> customerOptional =  wxTempUserRepository.findByCondition(condition).stream().findFirst();
        return customerOptional;
    }

    public Optional<WxOrderingUser> getWxOrderingUserByOpenId(String openId) {
        Condition condition = new Condition(WxOrderingUser.class);
        condition.or().andEqualTo("openidOrdering", openId);
        Optional<WxOrderingUser> customerOptional =  wxOrderingUserRepository.findByCondition(condition).stream().findFirst();
        return customerOptional;
    }

    public String getPhoneByWXCode(String code, String encryptedData, String iv){
        SessionDTO dto =  wxAppHelper.getSession(code, WxAppHelper.APPID, WxAppHelper.SECRET);
        String phone = wxAppHelper.decryptPhone(dto.getSessionKey(), encryptedData, iv);

        return phone;
    }

    public CustomerVO authorizeTemp(String code){
        SessionDTO dto =  wxAppHelper.getSession(code,WxAppHelper.APPID,WxAppHelper.SECRET);
        String token = WXTokenService.buildToken(dto.getOpenId(), dto.getSessionKey());

        Optional<WxTempUser> WxCustomerOptional = getWxTempUserByOpenId(dto.getOpenId());

        if(WxCustomerOptional.isPresent()){
            WxTempUser wxTempUser = WxCustomerOptional.get();
            //微信只要获取code,原SessionKey会失效
            wxTempUser.setSessionkey(dto.getSessionKey());
            wxTempUser.setToken(token);
            wxTempUserRepository.update(wxTempUser);
            if (wxTempUser.getPhone()==null){
                return _getWxTempUserVO(dto.getOpenId());
            }else {
                Optional<Customer> customerOptional = customerService.findCustomerByOpenId(dto.getOpenId());
                if (customerOptional.isPresent()) {
                    Customer customer = customerOptional.get();
                    customer.setSessionkey(dto.getSessionKey());
                    customer.setToken(token);
                    customerRepository.update(customer);
                    CustomerVO customerVO = _getCustomerVO(dto.getOpenId());
                    customerVO.setUserId(customerVO.getCustomerId());
                    return customerVO;
                }else {
                    CustomerVO customerVO = _getWxTempUserVO(dto.getOpenId());

                    return customerVO;
                }
            }
        } else {
            WxTempUser wxTempUser = new WxTempUser();
            wxTempUser.setOpenid(dto.getOpenId());
            //微信只要获取code,原SessionKey会失效
            wxTempUser.setSessionkey(dto.getSessionKey());
            wxTempUser.setToken(token);
            wxTempUserRepository.save(wxTempUser);
            return _getWxTempUserVO(dto.getOpenId());
        }

    }

    public CustomerVO authorizeOrdering(String code){
        SessionDTO dto =  wxAppHelper.getSession(code,WxAppHelper.ORDERINGAPPID,WxAppHelper.ORDERINGSECRET);
        String token = WXTokenService.buildToken(dto.getOpenId(), dto.getSessionKey());
        Optional<WxOrderingUser> customerOptional = getWxOrderingUserByOpenId(dto.getOpenId());

        if(customerOptional.isPresent()){
            WxOrderingUser wxOrderingUser = customerOptional.get();
            //微信只要获取code,原SessionKey会失效
            wxOrderingUser.setSessionkey(dto.getSessionKey());
            wxOrderingUser.setToken(token);
            wxOrderingUserRepository.update(wxOrderingUser);
            if (wxOrderingUser.getPhone() == null){
                return _getWxOrderingUserVO(dto.getOpenId());
            }else {
                return _getCustomerVOByOrderingOpenID(dto.getOpenId());
            }
        } else {
            WxOrderingUser wxOrderingUser = new WxOrderingUser();
            wxOrderingUser.setOpenidOrdering(dto.getOpenId());
            wxOrderingUser.setSessionkey(dto.getSessionKey());
            wxOrderingUser.setToken(token);
            wxOrderingUserRepository.save(wxOrderingUser);
            return _getWxOrderingUserVO(dto.getOpenId());
        }
    }


    public void userInfoDetail(UserInfoDetailForm userInfoDetailForm){
        Optional<WxTempUser> customerOptional = getWxTempUserByOpenId(userInfoDetailForm.getOpenId());

        if(customerOptional.isPresent()){
            WxTempUser customer = customerOptional.get();
            customer.setOpenid(userInfoDetailForm.getOpenId());
            customer.setName(userInfoDetailForm.getNickName());
            customer.setGender(Integer.valueOf(userInfoDetailForm.getGender()).byteValue());
            customer.setCity(userInfoDetailForm.getCity());
            customer.setProvince(userInfoDetailForm.getProvince());
            customer.setThumbnail(userInfoDetailForm.getAvatarUrl());
            wxTempUserRepository.update(customer);
        }else {
            WxTempUser wxTempUser = new WxTempUser();
            wxTempUser.setOpenid(userInfoDetailForm.getOpenId());
            wxTempUser.setName(userInfoDetailForm.getNickName());
            wxTempUser.setGender(Integer.valueOf(userInfoDetailForm.getGender()).byteValue());
            wxTempUser.setCity(userInfoDetailForm.getCity());
            wxTempUser.setProvince(userInfoDetailForm.getProvince());
            wxTempUser.setThumbnail(userInfoDetailForm.getAvatarUrl());
            //微信只要获取code,原SessionKey会失效
            wxTempUserRepository.save(wxTempUser);
        }

    }

    public void userInfoDetailOrdering(UserInfoDetailForm userInfoDetailForm){
        Optional<WxOrderingUser> customerOptional = getWxOrderingUserByOpenId(userInfoDetailForm.getOpenId());

        if(customerOptional.isPresent()){
            WxOrderingUser customer = customerOptional.get();
            customer.setOpenidOrdering(userInfoDetailForm.getOpenId());
            customer.setName(userInfoDetailForm.getNickName());
            customer.setGender(Integer.valueOf(userInfoDetailForm.getGender()).byteValue());
            customer.setCity(userInfoDetailForm.getCity());
            customer.setProvince(userInfoDetailForm.getProvince());
            customer.setThumbnail(userInfoDetailForm.getAvatarUrl());
            wxOrderingUserRepository.update(customer);
        }else {
            throw new ServiceException(WX_CUSTOMER_NOT_EXIST);
        }

    }

    public CustomerVO authorize(String code){
        SessionDTO dto =  wxAppHelper.getSession(code,WxAppHelper.APPID,WxAppHelper.SECRET);
        String token = WXTokenService.buildToken(dto.getOpenId(), dto.getSessionKey());
        Optional<Customer> customerOptional = customerService.findCustomerByOpenId(dto.getOpenId());

        if(customerOptional.isPresent()){
            Customer customer = customerOptional.get();
            //微信只要获取code,原SessionKey会失效
            customer.setSessionkey(dto.getSessionKey());
            customer.setToken(token);
            customerRepository.update(customer);
            return _getCustomerVO(dto.getOpenId());
        } else {
            Customer customer = new Customer();
            customer.setOpenid(dto.getOpenId());
            customer.setSessionkey(dto.getSessionKey());//微信只要获取code,原SessionKey会失效
            customer.setToken(token);
            customerRepository.save(customer);
            return _getCustomerVO(dto.getOpenId());
        }

    }


    public CustomerVO userInfo(String openId, String encryptedData, String iv){
        Optional<Customer> customerOptional = customerService.findCustomerByOpenId(openId);
        if(customerOptional.isPresent()){
            Customer customer = customerOptional.get();
            UserInfoDTO dto = wxAppHelper.decryptUserInfo(customer.getSessionkey(), encryptedData, iv);
            customer.setName(dto.getNickName());
            customer.setGender(dto.getGender().byteValue());
            customer.setCity(dto.getCity());
            customer.setProvince(dto.getProvince());
            customer.setThumbnail(dto.getAvatarUrl());
            customer.setUnionid(dto.getUnionId());
            customerRepository.update(customer);
            return _getCustomerVO(openId);
        }else {
            throw new ServiceException(WX_CUSTOMER_NOT_EXIST);
        }

    }

    public CustomerVO wxPhone(String openId, String encryptedData, String iv){
        Optional<Customer> customerOptional = customerService.findCustomerByOpenId(openId);
        if(customerOptional.isPresent()){
            Customer customer = customerOptional.get();
            String phone = wxAppHelper.decryptPhone(customer.getSessionkey(), encryptedData, iv);
            customer.setPhone(phone);
            customerRepository.update(customer);
            return _getCustomerVO(openId);
        }else {
            throw new ServiceException(WX_CUSTOMER_NOT_EXIST);
        }
    }


    public CustomerVO wxTempUserPhone(String openId, String encryptedData, String iv){
        Optional<WxTempUser> wxTempUserOptional = getWxTempUserByOpenId(openId);
        if(wxTempUserOptional.isPresent()){
            WxTempUser wxTempUser = wxTempUserOptional.get();
            String phone = wxAppHelper.decryptPhone(wxTempUser.getSessionkey(), encryptedData, iv);
            wxTempUser.setPhone(phone);
            wxTempUserRepository.update(wxTempUser);


            Optional<Customer> customerOptional = customerService.findCustomerByOpenId(openId);

            if (customerOptional.isPresent()) {
                Customer customer = customerOptional.get();
                if (StringUtils.isEmpty(customer.getPhone())) {
                    customer.setPhone(phone);

                    customerRepository.update(customer);
                }
            } else {

                Condition condition = new Condition(Customer.class);
                condition.or().andEqualTo("phone", phone);
                Optional<Customer> customerWithPhoneOptional = customerRepository.findByCondition(condition).stream().findFirst();


                if (customerWithPhoneOptional.isPresent()) {
                    Customer customer = customerWithPhoneOptional.get();
                    customer.setOpenid(openId);
                    customerRepository.update(customer);
                } else {
                    Customer customer = new Customer();
                    BeanUtils.copyProperties(wxTempUser, customer);
                    customer.setId(null);
                    customerRepository.save(customer);
                }
            }
            return _getCustomerVO(openId);
        }else {
            throw new ServiceException(WX_CUSTOMER_NOT_EXIST);
        }
    }

    public CustomerVO wxOrderingUserPhone(String openId, String encryptedData, String iv){
        Optional<WxOrderingUser> wxOrderingUserOptional = getWxOrderingUserByOpenId(openId);
        if(wxOrderingUserOptional.isPresent()){
            WxOrderingUser wxOrderingUser = wxOrderingUserOptional.get();
            String phone = wxAppHelper.decryptPhone(wxOrderingUser.getSessionkey(), encryptedData, iv);
            wxOrderingUser.setPhone(phone);
            wxOrderingUserRepository.update(wxOrderingUser);


            Optional<Customer> customerOptional = customerService.findCustomerByOrderingOpenId(openId);

            if (customerOptional.isPresent()) {
                Customer customer = customerOptional.get();
                if (StringUtils.isEmpty(customer.getPhone())) {
                    customer.setPhone(phone);
                    customerRepository.update(customer);
                }
            } else {
                Condition condition = new Condition(Customer.class);
                condition.or().andEqualTo("phone", phone);
                Optional<Customer> customerWithPhoneOptional = customerRepository.findByCondition(condition).stream().findFirst();
                if (customerWithPhoneOptional.isPresent()) {
                    Customer customer = customerWithPhoneOptional.get();
                    customer.setOpenidOrdering(openId);
                    customerRepository.update(customer);
                } else {
                    Customer customer = new Customer();
                    BeanUtils.copyProperties(wxOrderingUser, customer);
                    customer.setId(null);
                    customerRepository.save(customer);
                }
            }
            return _getCustomerVOByOrderingOpenID(openId);
        }else {
            throw new ServiceException(WX_CUSTOMER_NOT_EXIST);
        }
    }

    public CustomerVO saveWxTempUserPhone(String openId, String phone){
        Optional<WxTempUser> wxTempUserOptional = getWxTempUserByOpenId(openId);
        if(wxTempUserOptional.isPresent()){
            WxTempUser wxTempUser = wxTempUserOptional.get();
            wxTempUser.setPhone(phone);
            wxTempUserRepository.update(wxTempUser);


            Optional<Customer> customerOptional = customerService.findCustomerByOpenId(openId);

            if (customerOptional.isPresent()) {
                Customer customer = customerOptional.get();
                if (StringUtils.isEmpty(customer.getPhone())) {
                    customer.setPhone(phone);

                    customerRepository.update(customer);
                }
            } else {

                Condition condition = new Condition(Customer.class);
                condition.or().andEqualTo("phone", phone);
                Optional<Customer> customerWithPhoneOptional = customerRepository.findByCondition(condition).stream().findFirst();


                if (customerWithPhoneOptional.isPresent()) {
                    Customer customer = customerWithPhoneOptional.get();
                    customer.setOpenid(openId);
                    customerRepository.update(customer);
                } else {
                    Customer customer = new Customer();
                    BeanUtils.copyProperties(wxTempUser, customer);
                    customer.setId(null);
                    customerRepository.save(customer);
                }


            }
            return _getCustomerVO(openId);
        }else throw new ServiceException(WX_CUSTOMER_NOT_EXIST);
    }


    public CustomerVO updatePhone(Integer customerId, String phone){
        Customer customer = customerRepository.findById(customerId);
        if(customer != null){
            customer.setPhone(phone);
            customerRepository.update(customer);
            return _getCustomerVO(customer.getOpenid());
        }else throw new ServiceException(WX_CUSTOMER_NOT_EXIST);
    }

    public Customer createCustomer(Integer shopID,String customerID,String customerName){
        Customer customer = new Customer();
        customerID = shopID+"_"+customerID;
        customer.setShopCustomerid(customerID);
        customer.setName(customerName);
        customerRepository.save(customer);
        Optional<Customer> customerOptional = customerService.findCustomerByShopCustomerID(customerID);
        customer = customerOptional.get();
        return customer;
    }

    private CustomerVO _getCustomerVO(String openId){
        return customerService.findCustomerByOpenId(openId).map(c ->
                CustomerVO.builder()
                        .name(c.getName())
                        .phone(c.getPhone())
                        .openId(c.getOpenid())
                        .thumbnail(c.getThumbnail())
                        .customerId(c.getId())
                        .token(c.getToken()).build()
        ).orElseThrow(() -> new ServiceException(WX_CREATE_CUSTOMER));

    }

    private CustomerVO _getCustomerVOByOrderingOpenID(String openId){
        return customerService.findCustomerByOrderingOpenId(openId).map(c ->
                CustomerVO.builder()
                        .name(c.getName())
                        .phone(c.getPhone())
                        .openId(c.getOpenidOrdering())
                        .thumbnail(c.getThumbnail())
                        .customerId(c.getId())
                        .token(c.getToken()).build()
        ).orElseThrow(() -> new ServiceException(WX_CREATE_CUSTOMER));

    }




    private CustomerVO _getWxTempUserVO(String openId){

        Condition condition = new Condition(WxTempUser.class);
        condition.or().andEqualTo("openid", openId);
        Optional<WxTempUser> customerOptional =  wxTempUserRepository.findByCondition(condition).stream().findFirst();

        return customerOptional.map(c ->
                CustomerVO.builder()
                        .name(c.getName())
                        .phone(c.getPhone())
                        .openId(c.getOpenid())
                        .thumbnail(c.getThumbnail())
                        .customerId(c.getId())
                        .token(c.getToken()).build()
        ).orElseThrow(() -> new ServiceException(WX_CREATE_CUSTOMER));

    }

    private CustomerVO _getWxOrderingUserVO(String openId){

        Condition condition = new Condition(WxOrderingUser.class);
        condition.or().andEqualTo("openidOrdering", openId);
        Optional<WxOrderingUser> customerOptional =  wxOrderingUserRepository.findByCondition(condition).stream().findFirst();

        return customerOptional.map(c ->
                CustomerVO.builder()
                        .name(c.getName())
                        .phone(c.getPhone())
                        .openId(c.getOpenidOrdering())
                        .thumbnail(c.getThumbnail())
                        .customerId(c.getId())
                        .token(c.getToken()).build()
        ).orElseThrow(() -> new ServiceException(WX_CREATE_CUSTOMER));

    }


}
